package bll

import (
	"fmt"
	"jgt-oper/src/model"
	"jgt-oper/src/schema"
	"jgt-oper/src/util"
	"sync"
	"time"

	"github.com/pkg/errors"
)

// Menu 菜单管理
type Menu struct {
	sync.RWMutex
	MenuModel model.IMenu `inject:"IMenu"`
}

// GetLevelCode 获取分级码
func (a *Menu) GetLevelCode(parentID string) (string, error) {
	items, err := a.MenuModel.QueryByParentIDOrderLevelCode(parentID)
	if err != nil {
		return "", err
	} else if len(items) == 0 {
		if parentID == "" {
			return "01", nil
		}
		item, verr := a.Get(parentID)
		if verr != nil {
			return "", verr
		} else if item == nil {
			return "", errors.New("无效的上级")
		}
		return item.LevelCode + "01", nil
	}

	levelCode := items[0].LevelCode
	root := levelCode[:len(levelCode)-2]
	toValue := func(i int) string {
		if i < 10 {
			return fmt.Sprintf("%s0%d", root, i)
		}
		return fmt.Sprintf("%s%d", root, i)
	}

	for i, l := 1, len(items); i < 100; i++ {
		code := toValue(i)
		if i <= l &&
			items[i-1].LevelCode == code {
			continue
		}
		return code, nil
	}

	return "", errors.New("获取分级码发生错误")
}

// QueryPage 查询分页数据
func (a *Menu) QueryPage(params schema.MenuQueryParam, pageIndex, pageSize uint) (int64, []*schema.Menu, error) {
	return a.MenuModel.QueryPage(params, pageIndex, pageSize)
}

// QueryTree 查询树形数据
func (a *Menu) QueryTree(params schema.MenuSelectParam) ([]map[string]interface{}, error) {
	items, err := a.MenuModel.QuerySelect(params)
	if err != nil {
		return nil, err
	}

	mapItems := make([]map[string]interface{}, len(items))
	for i, item := range items {
		mapItems[i] = util.StructToMap(item)
	}

	treeItems := util.Slice2Tree(mapItems, "record_id", "parent_id")
	return util.ConvertToViewTree(treeItems, "name", "record_id", "record_id"), nil
}

// Get 精确查询数据
func (a *Menu) Get(recordID string) (*schema.Menu, error) {
	return a.MenuModel.Get(recordID)
}

// Create 创建数据
func (a *Menu) Create(item *schema.Menu) error {
	a.Lock()
	defer a.Unlock()

	if item.Code != "" {
		exists, verr := a.MenuModel.CheckCode(item.Code, item.Type, item.ParentID)
		if verr != nil {
			return verr
		} else if exists {
			return errors.New("菜单编号已经存在")
		}
	}

	if item.Type == 10 {
		item.ParentID = ""
	}

	levelCode, err := a.GetLevelCode(item.ParentID)
	if err != nil {
		return err
	}

	item.LevelCode = levelCode
	item.ID = 0
	item.RecordID = util.UUID()
	item.Created = time.Now().Unix()
	item.Deleted = 0
	return a.MenuModel.Create(item)
}

// Update 更新数据
func (a *Menu) Update(recordID string, item *schema.Menu) error {
	a.Lock()
	defer a.Unlock()

	if item.Type == 10 {
		item.ParentID = ""
	}

	oldItem, err := a.Get(recordID)
	if err != nil {
		return err
	} else if oldItem == nil {
		return nil
	}

	if item.Code != "" && item.Code != oldItem.Code {
		exists, verr := a.MenuModel.CheckCode(item.Code, item.Type, item.ParentID)
		if verr != nil {
			return verr
		} else if exists {
			return errors.New("菜单编号已经存在")
		}
	}

	// 优先更新分级码
	if item.ParentID != oldItem.ParentID {
		levelCode, verr := a.GetLevelCode(item.ParentID)
		if verr != nil {
			return verr
		}

		verr = a.MenuModel.UpdateLevelCode(oldItem.LevelCode, levelCode)
		if verr != nil {
			return verr
		}
	}

	info := util.StructToMap(item)
	delete(info, "id")
	delete(info, "record_id")
	delete(info, "creator")
	delete(info, "created")
	delete(info, "deleted")
	delete(info, "level_code")

	return a.MenuModel.Update(recordID, info)
}

// UpdateStatus 更新状态
func (a *Menu) UpdateStatus(recordID string, status int) error {
	info := map[string]interface{}{
		"status": status,
	}

	return a.MenuModel.Update(recordID, info)
}

// Delete 删除数据
func (a *Menu) Delete(recordID string) error {
	exists, err := a.MenuModel.CheckChild(recordID)
	if err != nil {
		return err
	} else if exists {
		return errors.New("含有下级菜单，不能删除")
	}

	return a.MenuModel.Delete(recordID)
}

// GetLevelCodeBySystemCode 根据系统编号获取分级码
func (a *Menu) GetLevelCodeBySystemCode(code string) (string, error) {
	item, err := a.MenuModel.GetByCodeAndType(code, 10)
	if err != nil {
		return "", err
	} else if item == nil {
		return "", errors.New("未知的系统编号")
	}
	return item.LevelCode, nil
}

// QueryBySystemCode 根据系统编号查询菜单数据
func (a *Menu) QueryBySystemCode(code string) ([]*schema.Menu, error) {
	levelCode, err := a.GetLevelCodeBySystemCode(code)
	if err != nil {
		return nil, err
	}

	items, err := a.MenuModel.QueryChildsByLevelCode(levelCode)
	if err != nil {
		return nil, err
	}
	return items, nil
}

// QueryBySystemCodeAndIDs 根据系统编号和菜单ID查询数据
func (a *Menu) QueryBySystemCodeAndIDs(code string, recordIDs []string) ([]*schema.Menu, error) {
	sysLevelCode, err := a.GetLevelCodeBySystemCode(code)
	if err != nil {
		return nil, err
	}

	codes, err := a.MenuModel.QueryLevelCodesByLevelCodeAndIDs(sysLevelCode, recordIDs)
	if err != nil {
		return nil, err
	}

	var newLevelCodes []string
	for _, code := range codes {
		pcodes := util.ParseLevelCodes(code)
		for _, p := range pcodes {
			if p == sysLevelCode {
				continue
			}
			newLevelCodes = append(newLevelCodes, p)
		}
	}

	return a.MenuModel.QueryByLevelCodes(newLevelCodes)
}

// ConvToTreeData 转换为树形数据
func (a *Menu) ConvToTreeData(menus []*schema.Menu, hasAction bool) ([]map[string]interface{}, error) {
	mdatas := make([]map[string]interface{}, len(menus))
	for i, menu := range menus {
		mdatas[i] = map[string]interface{}{
			"record_id":  menu.RecordID,
			"parent_id":  menu.ParentID,
			"name":       menu.Name,
			"code":       menu.Code,
			"level_code": menu.LevelCode,
			"icon":       menu.Icon,
			"router":     menu.Router,
			"type":       menu.Type,
		}
	}

	treeDatas := util.Slice2Tree(mdatas, "record_id", "parent_id")
	if hasAction {
		a.convActionTree(&treeDatas)
	}

	return treeDatas, nil
}

// 遍历菜单树，将功能的子级转换为动作数组
func (a *Menu) convActionTree(child *[]map[string]interface{}) {
	for _, c := range *child {
		if util.TT(c["type"]).Int() == 30 {
			children, ok := c["children"]
			if ok {
				delete(c, "children")
				childActions := *children.(*[]map[string]interface{})
				actions := make([]map[string]interface{}, len(childActions))

				for i, c := range childActions {
					actions[i] = map[string]interface{}{
						"record_id":  c["record_id"],
						"level_code": c["level_code"],
						"code":       c["code"],
						"name":       c["name"],
						"router":     c["router"],
					}
				}

				c["actions"] = actions
			}
			continue
		}

		if children, ok := c["children"]; ok {
			a.convActionTree(children.(*[]map[string]interface{}))
		}
	}
}

// QueryByIDs 根据ID列表查询菜单数据
func (a *Menu) QueryByIDs(recordIDs []string) ([]*schema.Menu, error) {
	return a.MenuModel.QueryByIDs(recordIDs)
}
